﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using QntPlatform.Strategy;
namespace QntPlatform.Strategy.CmdCtrl
{
    /*
     * 行情分析
     * 触发命令
     * 分析命令
     * 买入：行情信息、账户信息
     * 设置止损
     * 设置止盈
     * 监测止损
     * 监测止盈
     * ------------
     * 管道添加--事件处理
     * */
    /// <summary>
    /// 标准信号做单，使用3步止盈
    /// </summary>
    public class TrailingGroup3 : CmdHandlePart, ICmdCtrl
    {
        decimal stopLossRatio = 0.02m;

       
        public TrailingGroup3(StrategyBase parent) : base(parent)
        {

        }
        void Buy(TradeCmd cmdVal)
        {
            var isLong = cmdVal.IsLong;
            //计算仓位
            var re = Exchange.GetRecordsAsync(cmdVal.Period);
            var tck = Exchange.GetTickerAsync();
            var account = Exchange.GetAccountAsync();
            var kArr = re.Result;
            //var minLow = kArr.Skip(kArr.Length - 7).Min(p => p.Low); // Aggregate((p1, p2) =>(p1 == null || p1.Low > p2.Low)?p2:p1);
            //var atr = (decimal)TA.ATR(kArr, 14).Last();
            decimal stopLoss = StopLossCalc(kArr, isLong);// minLow - atr * 0.5m; //止损价

            var nowPrice = tck.Result.Buy;
            var buyAmount = AmountCalc(account.Result.Balance, stopLoss, nowPrice, isLong);// account.Result.Balance * stopLossRatio / (nowPrice - stopLoss);
            
            log.Debug("交易信息计算",new { stopLoss,nowPrice,buyAmount,stopLossRatio });
            //计算止盈止损


            //买卖
            var id = execTrade(DirectionTo.InFor(isLong),buyAmount,GetHashCode()); //  Exchange.BuyAsync(buyAmount);
            //止盈止损添加
            var auto = new TvCmdHandler.AutoSellOrder();
            if (cmdVal.sells.Length != 2)
                throw new QntException("止盈数量错误");
            auto.SourcePrice = nowPrice;
            auto.ProfitPrices = cmdVal.sells;
            auto.SourceOrderId = id+":"+ GetHashCode();
            auto.SourceAmount = buyAmount;
            auto.Amount = buyAmount;
            auto.Direction = SideDirection.CloseBuy;
            auto.StopLossPrice = stopLoss;
             
           var fun= new MiddleGuoup<Ticker>()
                //.AddUse( new StopLoss(auto, this).Execute)
                .AddRun(new StepProfit(this, auto).TickerChangeListening)
                .Bulid();
            ev = (p1, p2) => fun.Invoke(p2);
            Exchange.TickerChangeEvent += ev;
        }
        EventHandler<Ticker> ev;
        public override void OnExit(Exception ex)
        {
            Exchange.TickerChangeEvent -= ev;
        }

        private decimal AmountCalc(decimal balance, decimal stopLoss, decimal nowPrice, bool isLong)
        {
            var longVal = isLong ? 1 : -1;
            var am = longVal * balance * stopLossRatio / (nowPrice - stopLoss);
            return Exchange.getAmount(am);
        }

        private decimal StopLossCalc(Record[] records, bool isLong)
        {
            var last7 = records.Skip(records.Length - 7); // Aggregate((p1, p2) =>(p1 == null || p1.Low > p2.Low)?p2:p1);
            var top = isLong ? last7.Min(p => p.Low) : last7.Max(p => p.High);
            var atr = (decimal)TA.ATR(records, 14).Last();
            var atrV = isLong ? -atr * 0.5m : atr * 0.5m;
            var stopLoss = top + atrV; //止损价
            log.Debug("止损计算信息", new { stopLoss,top, atr });
            return stopLoss;
        }

  
        public bool Execute(CmdContext context = null)
        {
            var info = GetCmdValue<TradeCmd>(context.Cmd.Value);
            var trend = getTrend(info.Period);
            int cmdTrandNum = info.IsLong ? 1 : -1;
            if (!(trend == cmdTrandNum || trend == 2))
            {
                log.Debug("趋势不符，忽略交易命令", new { context.Cmd, trend });
                return true;
            }
            Buy(info);
            return true;

            //if (info.IsLong)
            //    Buy(info);
            //else
            //    SellShort(info);
            //return true;
        }

        public class TradeCmd
        {
            public decimal? Price { get; set; }
            public decimal[] sells { get; set; }
            public int Period { get; set; }
            public bool IsLong { get; set; }
        }
    }
}
